/*
 * PhotonRTOS础光实时操作系统 -- 中断实现文件
 *
 * Copyright (C) 2022, 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Baoyou Xie <xiebaoyou@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <photon/init.h>
#include <photon/sched.h>

#include <asm/irq.h>
#include <asm/irqflags.h>
#include <photon/irqflags.h>
#include <asm/processor.h>
#include <photon/irq.h>
#include <std/IfxSrc.h>
#include <IfxInt_reg.h>
#include <autosar/internal.h>
#include <photon/smp_lock.h>
#include <asm/mpu.h>

#include <Ifx_Ssw.h>

static void OsTaskSwIntHandler_Cpu0(void)
{
	os_check_async_action();
    IfxSrc_clearRequest(&SRC_GPSR_GPSR0_SR0);
}

static void OsTaskSwIntHandler_Cpu1(void)
{
	os_check_async_action();
    IfxSrc_clearRequest(&SRC_GPSR_GPSR0_SR1);
}

static void OsShutdownIntHandler_Cpu0(void)
{
	IfxSrc_clearRequest(&SRC_GPSR_GPSR0_SR2);
	/* 关闭核心 */
	autosar_shutdown_core();
}

static void OsShutdownIntHandler_Cpu1(void)
{
	IfxSrc_clearRequest(&SRC_GPSR_GPSR0_SR3);
	/* 关闭核心 */
	autosar_shutdown_core();
}

extern void smp_call_ioc_isr(void);

static void OsIocIntHandler_Cpu0(void)
{
	smp_call_ioc_isr();
	IfxSrc_clearRequest(&SRC_GPSR_GPSR0_SR4);
}

static void OsIocIntHandler_Cpu1(void)
{
	smp_call_ioc_isr();
	IfxSrc_clearRequest(&SRC_GPSR_GPSR0_SR5);
}

IFX_INTERRUPT(OsTaskSwIntHandler_Cpu0, 0, ISR_PRIORITY_CORE_INTER_CORE0);
IFX_INTERRUPT(OsTaskSwIntHandler_Cpu1, 1, ISR_PRIORITY_CORE_INTER_CORE1);

IFX_INTERRUPT(OsShutdownIntHandler_Cpu0, 0, ISR_PRIORITY_CORE_SHUTDOWN_CORE0);
IFX_INTERRUPT(OsShutdownIntHandler_Cpu1, 1, ISR_PRIORITY_CORE_SHUTDOWN_CORE1);

IFX_INTERRUPT(OsIocIntHandler_Cpu0, 0, ISR_PRIORITY_CORE_IOC_CORE0);
IFX_INTERRUPT(OsIocIntHandler_Cpu1, 1, ISR_PRIORITY_CORE_IOC_CORE1);

static  void __OSResumeExecution(void) {
	__asm__ volatile (
	           "   rslcx\n");
	return;
}

void arch_switch_cpu_context(struct task_desc *prev,
	struct task_desc *next)
{
	__asm__ volatile ("svlcx" : ::"memory");
	__tc397_switch_cpu_context(prev, next);
}

void __tc397_switch_cpu_context(struct task_desc *prev,
	struct task_desc *next)
{
	intptr_t prevLink;
	intptr_t currLink;
	intptr_t tmpLink;
	UCX_t *ptUpperCTX;
	LCX_t *cur_ctx;

	ptUpperCTX = (UCX_t*)GET_PHYS_ADDRESS(__mfcr(CPU_PCXI));

	if (prev->state == SUSPENDED) {
		currLink = ptUpperCTX->_PCXI;
		prevLink = __mfcr(CPU_FCX);

		cur_ctx = (LCX_t*)GET_PHYS_ADDRESS(currLink);

		while (cur_ctx->_PCXI != 0u)
		{
			tmpLink = cur_ctx->_PCXI;
			cur_ctx->_PCXI = prevLink;
			prevLink = currLink;
			currLink = tmpLink;
			cur_ctx = (LCX_t*)GET_PHYS_ADDRESS(currLink);
		}
		cur_ctx->_PCXI = prevLink;
		__mtcr(CPU_FCX, currLink);
		Ifx__isync();
		Ifx__dsync();
	}

	prev->task_spot.pcxi = ptUpperCTX->_PCXI;
	ptUpperCTX->_PCXI = next->task_spot.pcxi;

	__asm__ volatile  (
		   "mov.a\t %%a11, %0\n"
		   "ret\n"
		   : /* no outputs */ : "d"(__OSResumeExecution) : "a11");

    return;
}

void arch_irq_init()
{
	IfxSrc_init(&SRC_GPSR_GPSR0_SR0, IfxSrc_Tos_cpu0, ISR_PRIORITY_CORE_INTER_CORE0); ////cpu0异步激活，异步信号
	IfxSrc_enable(&SRC_GPSR_GPSR0_SR0);

	IfxSrc_init(&SRC_GPSR_GPSR0_SR1, IfxSrc_Tos_cpu1, ISR_PRIORITY_CORE_INTER_CORE1); //cpu1 异步激活，异步信号
	IfxSrc_enable(&SRC_GPSR_GPSR0_SR1);

	IfxSrc_init(&SRC_GPSR_GPSR0_SR2, IfxSrc_Tos_cpu0, ISR_PRIORITY_CORE_SHUTDOWN_CORE0); //cpu0 关机
	IfxSrc_enable(&SRC_GPSR_GPSR0_SR2);

	IfxSrc_init(&SRC_GPSR_GPSR0_SR3, IfxSrc_Tos_cpu1, ISR_PRIORITY_CORE_SHUTDOWN_CORE1); //cpu01关机
	IfxSrc_enable(&SRC_GPSR_GPSR0_SR3);

	IfxSrc_init(&SRC_GPSR_GPSR0_SR4, IfxSrc_Tos_cpu0, ISR_PRIORITY_CORE_IOC_CORE0); //cpu0 ioc
	IfxSrc_enable(&SRC_GPSR_GPSR0_SR4);

	IfxSrc_init(&SRC_GPSR_GPSR0_SR5, IfxSrc_Tos_cpu1, ISR_PRIORITY_CORE_IOC_CORE1); //cpu1 ioc
	IfxSrc_enable(&SRC_GPSR_GPSR0_SR5);

	Ifx__dsync();
	Ifx__isync();
}

void arch_task_init(void *stack, void* func, void *task)
{
	intptr_t ucx_link;
	intptr_t lcx_link;
	UCX_t *ucx;
	LCX_t *lcx;
	struct task_desc *tsk = (struct task_desc *)task;
	Ifx_CPU_PSW PSWRegisterValue;

    /* Unlink next two context's */
	ucx_link = __mfcr(CPU_FCX);
	ucx = (UCX_t*)GET_PHYS_ADDRESS(ucx_link);

	lcx_link = ucx->_PCXI;
	lcx = (LCX_t*)GET_PHYS_ADDRESS(lcx_link);
    __mtcr(CPU_FCX, lcx->_PCXI);

	PSWRegisterValue.U = 0;               /* Get the Program Status Word (PSW) register value         */
	PSWRegisterValue.B.PRS = PROTECTION_SET_1;             /* Set the PRS bitfield to enable the Protection Set        */

    ucx->_PCXI = NULL;
    ucx->_A10 = (uintptr_t)stack + (uintptr_t)THREAD_START_SP;
    ucx->_A11 = (uint32_t)func;
    ucx->_PSW = PSWRegisterValue.U | IFX_CFG_SSW_PSW_DEFAULT | (1 << IS_BIT_OFFSET) | 0x7f;
    lcx->_PCXI = GET_UPPER_CTX_LINK(ucx_link);
    lcx->_A11 = (uint32_t)func;
    tsk->task_spot.pcxi = GET_LOWER_CTX_LINK(lcx_link);
}
